#ifndef __SOCKET_H__
#define __SOCKET_H__

#include <memory>
#include <netinet/tcp.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "noncopyable.h"
#include "address.h"
#include "fd_manager.h"

class Socket : public std::enable_shared_from_this<Socket>, Noncopyable
{
public:
    typedef std::shared_ptr<Socket> ptr;
    typedef std::weak_ptr<Socket> weak_ptr;

    // Socket类型
    enum Type
    {
        // TCP 类型
        TCP = SOCK_STREAM,
        // UDP 类型
        UDP = SOCK_DGRAM
    };

    // Socket 协议族
    enum Family
    {
        // IPV4 socket
        IPV4 = AF_INET,
        // IPV6 socket
        IPV6 = AF_INET6,
        // Unix socket
        UNIX = AF_UNIX
    };

    Socket(int family, int type, int protocol = 0);
    ~Socket();

    // 创建TCP Socket(满足地址类型)
    static Socket::ptr CreateTCP(Address::ptr address);

    // 创建UDP Socket(满足地址类型)
    static Socket::ptr CreateUDP(Address::ptr address);

    // 创建IPv4的TCP Socket
    static Socket::ptr CreateTCPSocket();

    // 创建IPv4的UDP Socket
    static Socket::ptr CreateUDPSocket();

    // 创建IPv6的TCP Socket
    static Socket::ptr CreateTCPSocket6();

    // 创建IPv6的UDP Socket
    static Socket::ptr CreateUDPSocket6();

    // 创建Unix的TCP Socket
    static Socket::ptr CreateUnixTCPSocket();

    // 创建Unix的UDP Socket
    static Socket::ptr CreateUnixUDPSocket();

    // 获取发送超时时间(毫秒)
    uint64_t getSendTimeout();

    // 设置发送超时时间(毫秒)
    void setSendTimeout(uint64_t msec);

    // 获取接收超时时间(毫秒)
    uint64_t getRecvTimeout();

    // 设置接收超时时间(毫秒)
    void setRecvTimeout(uint64_t msec);

    // 获取sockopt getsockopt
    bool getOption(int level, int option, void *result, socklen_t *len);

    // 获取sockopt 模板 getsockopt
    template <class T>
    bool getOption(int level, int option, T &result)
    {
        socklen_t length = sizeof(T);
        return getOption(level, option, &result, &length);
    }

    // 设置sockoptsetsockopt
    bool setOption(int level, int option, const void *result, socklen_t len);

    // 设置sockopt 模板 setsockopt
    template <class T>
    bool setOption(int level, int option, const T &value)
    {
        return setOption(level, option, &value, sizeof(T));
    }

    // 接收connect连接
    virtual Socket::ptr accept();

    // 绑定地址
    virtual bool bind(const Address::ptr &addr);

    // 连接地址
    virtual bool connect(const Address::ptr &addr, uint64_t timeout_ms = -1);
    virtual bool reconnect(uint64_t timeout_ms = -1);

    // 监听socket
    virtual bool listen(int backlog = SOMAXCONN);

    // 关闭socket
    virtual bool close();

    // 发送数据
    virtual int send(const void *buffer, size_t len, int flags = 0);
    virtual int send(const iovec *buffers, size_t len, int flags = 0);
    virtual int sendTo(const void *buffer, size_t length, const Address::ptr to, int flags = 0);
    virtual int sendTo(const iovec *buffers, size_t length, const Address::ptr to, int flags = 0);

    // 接收数据
    virtual int recv(void *buffer, size_t length, int flags = 0);
    virtual int recv(iovec *buffers, size_t length, int flags = 0);
    virtual int recvFrom(void *buffer, size_t length, Address::ptr from, int flags = 0);
    virtual int recvFrom(iovec *buffer, size_t length, Address::ptr from, int flags = 0);

    // 获取远端地址
    Address::ptr getRemoteAddress();

    // 获取本地地址
    Address::ptr getLocalAddress();

    // 获取协议族
    int getFamily() const { return m_family; }

    // 获取类型
    int getType() const { return m_type; }

    // 获取协议
    int getProtocol() const { return m_protocol; }

    // 返回是否连接
    bool isConnected() const { return m_isConnected; }

    // 是否有效
    bool isValid() const { return m_socket != -1; }

    // 返回Socket 错误
    int getError();

    // 输出信息到流中
    virtual std::ostream &dump(std::ostream &os) const;

    virtual std::string toString() const;

    // 返回socket句柄
    int getSocket() const { return m_socket; }

    // 取消读
    bool cancelRead();

    // 取消写
    bool cancelWrite();

    // 取消accept
    bool cancelAccept();

    // 取消所有事件
    bool cancelAll();

protected:
    // 初始化socket
    void initSocket();

    // 创建socket
    void newSocket();

    // 初始化socket
    virtual bool init(int socket);

protected:
    // socket fd
    int m_socket;
    // 协议族
    int m_family;
    // 类型
    int m_type;
    // 协议
    int m_protocol;
    // 是否连接
    bool m_isConnected;
    // 本地地址
    Address::ptr m_localAddress;
    // 远端地址
    Address::ptr m_remoteAddress;
};

// 流式输出Socket
std::ostream &operator<<(std::ostream &os, const Socket &socket);

#endif